package com.eshipenet.shipnet.edgeboxrpc.grpc;


import com.eshipenet.shipnet.edgebox.grpc.*;
import com.eshipenet.shipnet.edgeboxrpc.service.EdgeBoxIdGenerator;
import com.eshipenet.shipnet.edgeboxrpc.util.FormatSql;
import com.eshipenet.shipnet.edgeboxrpc.util.GetJObjectUtil;
import com.eshipenet.shipnet.edgeboxrpc.util.PageUtil;
import com.eshipenet.shipnet.edgeboxrpc.util.TimestampToDate;
import com.google.protobuf.Struct;
import com.google.protobuf.Timestamp;
import com.google.protobuf.util.Timestamps;
import io.grpc.stub.StreamObserver;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.cache.query.FieldsQueryCursor;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.cache.query.SqlQuery;
import org.json4s.JsonAST;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.Option;
import scala.collection.Seq;
import scala.collection.immutable.List;
import squirrel.JSONQuery;
import squirrel.SqlValue;

import javax.cache.Cache;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;


public class EdgeBoxRepoGrpcImpl extends EdgeBoxRepoGrpc.EdgeBoxRepoImplBase {
  private Logger logger = LoggerFactory.getLogger("EdgeBoxRepoGrpcImpl");

  private IgniteCache<String, com.eshipenet.shipnet.edgebox.EdgeBox> cache;
  private EdgeBoxModelRepoGrpcImpl                                   modelRepoGrpc;
  private EdgeBoxIdGenerator                                         idGenerator;

  public EdgeBoxRepoGrpcImpl(IgniteCache<String, com.eshipenet.shipnet.edgebox.EdgeBox> cache, EdgeBoxIdGenerator idGenerator) {
    this.cache = cache;
    this.idGenerator = idGenerator;
  }

  /**
   * 查询列表
   *
   * @param req
   * @param responseObserver
   */
  public void findAll(EdgeBoxFindAllRequest req, StreamObserver<EdgeBoxFindAllReply> responseObserver) {

    try {
      logger.info("EdgeBoxRepoGrpcImpl.findAll.Filter {}",req.getFilter().toString());
      EdgeBoxFindAllReply reply = findAllInner(req);
      responseObserver.onNext(reply);
      responseObserver.onCompleted();

    } catch (Exception e) {
      responseObserver.onError(e);
    }

  }


  /**
   * 创建
   *
   * @param req
   * @param responseObserver
   */
  public void createOne(EdgeBoxCreateOneRequest req, StreamObserver<EdgeBoxCreateOneReply> responseObserver) {
    try {
      logger.info("EdgeBoxRepoGrpcImpl.createOne.data {}",req.getData());
      EdgeBoxCreateOneReply reply = createOneInner(req);
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }catch (Exception e){
      responseObserver.onError(e);
    }

  }


  /**
   * 修改
   *
   * @param req
   * @param responseObserver
   */
  public void updateOne(EdgeBoxUpdateOneRequest req, StreamObserver<EdgeBoxUpdateOneReply> responseObserver) {

    try {
      logger.info("EdgeBoxRepoGrpcImpl.updateOne.data {}",req.getData());
      EdgeBoxUpdateOneReply reply = updateOneInner(req);
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }catch (Exception e){
      responseObserver.onError(e);
    }

  }


  /**
   * 删除
   *
   * @param req
   * @param responseObserver
   */
  public void deleteOne(EdgeBoxDeleteOneRequest req, StreamObserver<EdgeBoxDeleteOneReply> responseObserver) {

    try {
      logger.info("EdgeBoxRepoGrpcImpl.deleteOne.id {}",req.getId());
      EdgeBoxDeleteOneReply reply = deleteOneInner(req);
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }catch (Exception e){
      responseObserver.onError(e);
    }

  }


  public EdgeBoxFindAllReply findAllInner(EdgeBoxFindAllRequest req) {

    int limit = req.getFilter().getLimit();
    int offset = req.getFilter().getOffset();

    if (limit == 0) {
      limit = 500;

    }
    if (offset == 0) {
      offset = 1;

    }


    //查询条件
    Struct wheres = req.getFilter().getWhere();

    JsonAST.JObject where = GetJObjectUtil.getWhere(wheres);

    //联合查询
    java.util.List<EdgeBoxFindAllFilterInclude> in_list = req.getFilter().getIncludeList();

    ArrayList<JsonAST.JValue> arrayList = new ArrayList<JsonAST.JValue>();
    for (int i = 0; i < in_list.size(); i++) {

      EdgeBoxFindAllFilterInclude include = in_list.get(i);

      JsonAST.JValue jValue = new JsonAST.JString(include.getName());

      arrayList.add(jValue);

    }

    List<JsonAST.JValue> includes_list = scala.collection.JavaConverters.asScalaIterator(arrayList.iterator()).toList();

    JsonAST.JArray includes = new JsonAST.JArray(includes_list);

    //生成查询列表的sql
    JSONQuery jsonQuery = JSONQuery.apply(new JsonAST.JString("edge_box"),
                                          Option.apply(where),
                                          Option.apply(new JsonAST.JString("*")),
                                          Option.apply(includes),
                                          Option.apply(null),
                                          Option.apply(null));

    Map<String, Object> map = FormatSql.getFormatSql(jsonQuery);

    String end_sql = map.get("sql").toString();

    SqlQuery<String, com.eshipenet.shipnet.edgebox.EdgeBox> sql =
      new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBox.class, end_sql);
    Seq<SqlValue> sqlValueSeq = (Seq<SqlValue>) map.get("args");
    sql.setArgs(FormatSql.sqlValueToObject(sqlValueSeq));
    logger.info("query EdgeBox list sql  {}",sql);
//    System.out.println(sql.getArgs()[0]);
//    sql.setArgs("dvxo92z5kJ0aZL6k");
    QueryCursor cursor = cache.query(sql);
//    java.util.List lst1 = cursor.getAll();
////    SqlQuery q = new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBox.class,
////                              "select * from edge_box where id = 'dvxo92z5kJ0aZL6k'");
////    java.util.List lst1 = cache.query(q).getAll();
//    System.out.println("size = " + lst1.size());
//    for (int i=0; i< lst1.size(); i++) {
//      System.out.println(lst1.get(i));
//    }
    //生成查询数据数量的sql
    JSONQuery jsonQuery1 = JSONQuery.apply(new JsonAST.JString("edge_box"),
                                           Option.apply(where),
                                           Option.apply(new JsonAST.JString("count(id) as count")),
                                           Option.apply(includes),
                                           Option.apply(null),
                                           Option.apply(null));

    Map<String, Object> count_sql = FormatSql.getFormatSql(jsonQuery1);

    String end_query = count_sql.get("sql").toString();

    SqlFieldsQuery sqlFieldsQuery = new SqlFieldsQuery(end_query);

    Seq<SqlValue> sqlValueSeq1 = (Seq<SqlValue>) count_sql.get("args");

    sqlFieldsQuery.setArgs(FormatSql.sqlValueToObject(sqlValueSeq1));
    logger.info("query EdgeBox count sql  {}",sqlFieldsQuery);

    //数据总数
    int totalCount = 0;

    try (FieldsQueryCursor<java.util.List<?>> cursor1 = cache.query(sqlFieldsQuery)) {

      for (java.util.List<?> row : cursor1) {
        totalCount = Integer.parseInt(row.get(0).toString());
      }
    }


    //分页工具
    Map<String, Object> page = PageUtil.page(limit, totalCount, offset);
    //起点数据
    int startIndex = (int) page.get("startIndex");
    //结点数据
    int endIndex = (int) page.get("endIndex");

    java.util.List<EdgeBoxEdge> list = new ArrayList<>();

    //判断是否有数据，无数据时直接返回
    if (totalCount < 1) {
      //设置分页信息
      PageInfo pageInfo = PageInfo.newBuilder()
                                  .setHasNextPage((Boolean) page.get("hasNextPage"))
                                  .setHasPreviousPage((Boolean) page.get("hasPreviousPage"))
                                  .build();

      EdgeBoxFindAllReply reply = EdgeBoxFindAllReply.newBuilder()
                                                     .setReq(req)
                                                     .setPageInfo(pageInfo)
                                                     .addAllEdges(list)
                                                     .setTotalCount(0).build();

      return reply;
    }

    Iterator<Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBox>> iterator = cursor.iterator();

    //计数器
    int times = 0;

    while (iterator.hasNext()) {

      Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBox> p = iterator.next();

      if (p != null && !p.equals("")) {

        if (list.size() < limit) {
          if (times >= startIndex && times < endIndex) {
            EdgeBoxEdge edgeBoxEdge = EdgeBoxEdge.newBuilder().setNode(EdgeBox
                                                                         .newBuilder()
                                                                         .setId(p.getKey())
                                                                         .setName(p.getValue().getName())
                                                                         .setCreatedAt(TimestampToDate.dateTotimestamp(p
                                                                                                                         .getValue()
                                                                                                                         .getCreatedAt()))
                                                                         .setUpdatedAt(TimestampToDate.dateTotimestamp(p
                                                                                                                         .getValue()
                                                                                                                         .getUpdatedAt()))
                                                                         .setModelId(p.getValue().getModelId())
                                                                         .setAvatar(p.getValue().getAvatar())
                                                                         .setDesc(p.getValue().getDesciption()))
                                                 .setCursor(p.getKey()).build();
            list.add(edgeBoxEdge);
          }

        } else {
          break;
        }
      }
      times++;
    }

    //设置分页信息
    PageInfo pageInfo = PageInfo.newBuilder()
                                .setHasNextPage((Boolean) page.get("hasNextPage"))
                                .setHasPreviousPage((Boolean) page.get("hasPreviousPage"))
                                .setStartCursor(page.get("startIndex").toString())
                                .setEndCursor(page.get("endIndex").toString())
                                .build();

    EdgeBoxFindAllReply reply = EdgeBoxFindAllReply.newBuilder()
                                                   .setReq(req)
                                                   .addAllEdges(list)
                                                   .setPageInfo(pageInfo)
                                                   .setTotalCount(totalCount).build();
    return reply;
  }


  public EdgeBoxCreateOneReply createOneInner(EdgeBoxCreateOneRequest req) {

    //获取当前时间
    java.sql.Timestamp createdAt = new java.sql.Timestamp(System.currentTimeMillis());
    Timestamp createdAt1 = Timestamps.fromMillis(new Date().getTime());

    String modelId = req.getData().getModelId();

    //判断modelId
    if (modelId != null && !modelId.equals("")) {

      int count = modelRepoGrpc.getModelCount(modelId);

      if (count < 1) {
        try {
          throw new Exception("modelId查询为空");
        } catch (Exception e) {
          e.printStackTrace();
        }

      }

    }

    //存进新纪录
    String id = this.idGenerator.generate();
    cache.put(id, new com.eshipenet.shipnet.edgebox.EdgeBox(
      req.getData().getName(),
      req.getData().getDesc(),
      req.getData().getAvatar(),
      createdAt,
      createdAt,
      null,
      req.getData().getModelId()
    ));

    EdgeBox edgeBox = EdgeBox.newBuilder()
                             .setId(id)
                             .setName(req.getData().getName())
                             .setCreatedAt(createdAt1)
                             .setAvatar(req.getData().getAvatar())
                             .setDesc(req.getData().getDesc())
                             .setModelId(req.getData().getModelId())
                             .setUpdatedAt(createdAt1)
                             .build();

    EdgeBoxCreateOneReply reply = EdgeBoxCreateOneReply.newBuilder().setData(edgeBox).setReq(req).build();
    return reply;
  }


  public EdgeBoxUpdateOneReply updateOneInner(EdgeBoxUpdateOneRequest req) {
    //获取当前时间
    java.sql.Timestamp updatedAt = new java.sql.Timestamp(System.currentTimeMillis());
    Timestamp updatedAt1 = Timestamps.fromMillis(new Date().getTime());

    //查询指定数据
    SqlQuery sql = new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBox.class, "id=?");

    QueryCursor<Cache.Entry<Integer, com.eshipenet.shipnet.edgebox.EdgeBox>> cursor =
      cache.query(sql.setArgs(req.getId()));
    logger.info("query EdgeBox list by id sql  {}",sql);
    Cache.Entry<Integer, com.eshipenet.shipnet.edgebox.EdgeBox> e = cursor.getAll().get(0);


    cache.put(req.getId(), new com.eshipenet.shipnet.edgebox.EdgeBox(
      req.getData().getName(),
      e.getValue().getDesciption(),
      e.getValue().getAvatar(),
      e.getValue().getCreatedAt(),
      updatedAt,
      updatedAt,
      e.getValue().getModelId()
    ));

    EdgeBox edgeBox = EdgeBox.newBuilder()
                             .setId(req.getId())
                             .setName(req.getData().getName())
                             .setCreatedAt(TimestampToDate.dateTotimestamp(e.getValue().getCreatedAt()))
                             .setUpdatedAt(updatedAt1)
                             .setAvatar(e.getValue().getAvatar())
                             .setModelId(e.getValue().getModelId())
                             .setDesc(e.getValue().getDesciption())
                             .build();

    EdgeBoxUpdateOneReply reply = EdgeBoxUpdateOneReply.newBuilder().setData(edgeBox).setReq(req).build();

    return reply;

  }


  public EdgeBoxDeleteOneReply deleteOneInner(EdgeBoxDeleteOneRequest req) {

    //查询指定数据
    SqlQuery sql = new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBox.class, "id=?");

    QueryCursor<Cache.Entry<Integer, com.eshipenet.shipnet.edgebox.EdgeBox>> cursor =
      cache.query(sql.setArgs(req.getId()));
    logger.info("query EdgeBox list by id sql  {}",sql);
    Cache.Entry<Integer, com.eshipenet.shipnet.edgebox.EdgeBox> e = cursor.getAll().get(0);

    EdgeBox edgeBox = EdgeBox.newBuilder()
                             .setId(req.getId())
                             .setName(e.getValue().getName())
                             .setCreatedAt(TimestampToDate.dateTotimestamp(e.getValue().getCreatedAt()))
                             .setUpdatedAt(TimestampToDate.dateTotimestamp(e.getValue().getUpdatedAt()))
                             .setAvatar(e.getValue().getAvatar())
                             .setModelId(e.getValue().getModelId())
                             .setDesc(e.getValue().getDesciption())
                             .build();

    SqlFieldsQuery query = new SqlFieldsQuery("delete from edgebox   where id=?");
    cache.query(query.setArgs(req.getId())).getAll();
    logger.info("delete EdgeBox  by id sql  {}",query);
    EdgeBoxDeleteOneReply reply = EdgeBoxDeleteOneReply.newBuilder().setData(edgeBox).setReq(req).build();

    return reply;

  }


  /**
   * 根据id查询数据数量
   *
   * @param id
   * @return
   */
  public int getEdgeBoxCount(String id) {

    //查询数据总数
    SqlFieldsQuery query = new SqlFieldsQuery("select count(id) from  edgebox where id=? ");

    query.setArgs(id);
    //数据总数
    java.util.List<?> getCount = cache.query(query).getAll().get(0);

    Object obj = getCount.get(0);

    int count = Integer.parseInt(obj.toString());

    return count;

  }


}
